package uk.ac.nott.cs.g53dia;

import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * An abstract base class for bees in the standard {@link Environment}.
 * 
 * @author Neil Madden.
 */
/*
 * Copyright (c) 2003 Stuart Reeves Copyright (c) 2003-2005 Neil Madden
 * (nem@cs.nott.ac.uk).
 * 
 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */
public abstract class Bee {
  
  public enum Role {
    QUEEN, NONQUEEN
  };

  public Bee(int id) {
    this.id = id;
  }

  /**
   * Sub-classes must implement this method to provide the "brains" for the bee.
   * 
   * @param view
   *          the cells the bee can currently see
   * @param timestep
   *          The current timestep
   * @return an action to perform
   */
  public abstract Action senseAndAct(Cell[][] view, long timestep);

  // Fields used by the environment
  /**
   * Energy level. Energy is used by flying and other actions. A bee can
   * replenish its energy by resting (1 unit per timestep) or by harvesting
   * flowers. Energy is also needed to lay eggs.
   */
  int energy = 200;

  /**
   * The maximum amount of energy a bee can have.
   */
  public final static int MAX_ENERGY = 200;

  /**
   * The distance a bee can "see".
   */
  public final static int VIEW_RANGE = 5;

  /**
   * Number of eggs this bee has laid.
   */
  int eggs_laid = 0;

  /**
   * Use energy - used by actions.
   */
  public void useEnergy(int amount) throws ActionFailedException {
    energy -= amount;
    if (energy <= 0) {
      throw new DeadBeeException("no energy");
    }
  }

  /**
   * How much energy does this bee have?
   */
  public int getEnergy() {
    return energy;
  }

  /**
   * The bee's current position in the environment.
   */
  Point position = new Point(0, 0); // Default to origin

  /**
   * Get the bee's current position in the environment.
   */
  public Point getPosition() {
    return (Point) position.clone();
  }

  // can be used only from clone method
  protected void setPosition(Point point) {
    this.position = point;
  }

  /**
   * Get the cell currently occupied by the bee.
   * 
   * @param view
   *          the cells the bee can currently see
   * @return a reference to the cell currently occupied by this bee
   */

  public Cell getCurrentCell(Cell[][] view) {
    return view[VIEW_RANGE][VIEW_RANGE];
  }
  
  public List<Bee> getVisibleBees() {
    return Environment.getInstance().getBeesForCommunication(getPosition(), VIEW_RANGE);
  }
  
  public List<Bee> getVisibleBees2() {
    return Environment.getInstance().getBeesForCommunication(getPosition(), VIEW_RANGE+1);
  }
  
  public List<Bee> getBeesOnMyCell() {
    return Environment.getInstance().getBeesForCommunication(getPosition(), 0);
  }

  public abstract int updateFlowersPositions(List<Set<Point>> flowersOfType);
  
  public abstract int updateFlowersYields(List<Map<Long, Integer>> samples);

  public abstract List<Set<Point>> getFlowersOfType();
  
  public abstract List<Map<Long, Integer>> getSamples();
  
  public abstract void communicate(Bee bee);

  public abstract Map<Point, Cell> getCells();
  
  public abstract Role getRole();

  public abstract void addCells(Map<Point, Cell> cells);

  private int id;

  @Override
  public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + id;
    return result;
  }

  @Override
  public boolean equals(Object obj) {
    if (this == obj)
      return true;
    if (obj == null)
      return false;
    if (getClass() != obj.getClass())
      return false;
    Bee other = (Bee) obj;
    if (id != other.id)
      return false;
    return true;
  }

  public int getId() {
    return id;
  }
  
//:]
  public int getLaid() { 
    return eggs_laid;
  }

  public abstract Bee clone();
}
